﻿#include "Misc.h"
#include "Graphics.h"
#include "WinFunc.h"

#pragma comment(lib,"d3d11.lib")
#pragma comment(lib,"D3DCompiler.lib")

namespace Base {

	Graphics* Graphics::s_Graphics = nullptr;

	Graphics::Graphics() {

		D_ASSERT(s_Graphics == nullptr, "graphics already create!");
		s_Graphics = this;

		m_clearColor[0] = 0;
		m_clearColor[1] = 0;
		m_clearColor[2] = 0;
		m_clearColor[3] = 1;
	}
	Graphics::~Graphics() {}

	void Graphics::Init(HWND hWnd, int width, int height) {

		DXGI_SWAP_CHAIN_DESC sd = {};
		sd.BufferDesc.Width = 0;  // 分辨率宽度
		sd.BufferDesc.Height = 0; // 分辨率高度
		sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;  // 缓冲区数据格式
		sd.BufferDesc.RefreshRate.Numerator = 0;
		sd.BufferDesc.RefreshRate.Denominator = 0;
		sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
		sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		sd.SampleDesc.Count = 1;
		sd.SampleDesc.Quality = 0;
		sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		sd.BufferCount = 1;
		sd.OutputWindow = hWnd;
		sd.Windowed = TRUE;
		sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;//  DXGI_SWAP_EFFECT_DISCARD;
		sd.Flags = 0;

		UINT swapCreateFlags = 0u;
#ifndef NDEBUG
		swapCreateFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif


		//#ifndef NDEBUG
		//		m_DebugInfoManager.Set();
		//#endif // !NDEBUG

		// 创建device 和 swapchain
		// 可以得到 device swapchain 和 context
		D_HRESULT(D3D11CreateDeviceAndSwapChain(
			nullptr,
			D3D_DRIVER_TYPE_HARDWARE,
			nullptr,
			swapCreateFlags,
			nullptr,
			0,
			D3D11_SDK_VERSION,
			&sd,
			&m_SwapChain,
			&m_Device,
			nullptr,
			&m_Context
		));

		// 获取 back buffer
		ComPtr<ID3D11Resource> backBuffer;

		// __uuidof( ID3D11Texture2D ) ??
		D_HRESULT(m_SwapChain->GetBuffer(0, __uuidof(ID3D11Resource), &backBuffer));

		// 创建 renderTargetView
		D_HRESULT(m_Device->CreateRenderTargetView(backBuffer.Get(), nullptr, &m_Target));

		// 创建深度模板纹理
		ComPtr<ID3D11Texture2D> depthStencilTexture2d;
		D3D11_TEXTURE2D_DESC descDepth = {};
		descDepth.Width = width;
		descDepth.Height = height;
		descDepth.MipLevels = 1u;
		descDepth.ArraySize = 1u;
		descDepth.Format = DXGI_FORMAT_D32_FLOAT;//DXGI_FORMAT_D32_FLOAT;
		descDepth.SampleDesc.Count = 1u;
		descDepth.SampleDesc.Quality = 0u;
		descDepth.Usage = D3D11_USAGE_DEFAULT;
		descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
		D_HRESULT(m_Device->CreateTexture2D(&descDepth, nullptr, &depthStencilTexture2d));

		// 创建深度模板视图
		/*D3D11_DEPTH_STENCIL_VIEW_DESC descDSV = {};
		descDSV.Format = DXGI_FORMAT_D32_FLOAT;
		descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
		descDSV.Texture2D.MipSlice = 0u;*/
		D_HRESULT(m_Device->CreateDepthStencilView(depthStencilTexture2d.Get(), nullptr, &m_DepthStencilView));

		// 绑定到设备
		// 注意 这里要使用 m_Target.GetAddressOf(), 不能使用 &m_Target
		m_Context->OMSetRenderTargets(1, m_Target.GetAddressOf(), m_DepthStencilView.Get());
		SetViewPort(0, 0, width, height);
	}

	void Graphics::Resize(int width, int height) {
		// 需要更新 backbuffer renderTargetView viewport 等
		m_Target.Reset();
		m_DepthStencilView.Reset();

		// 获取 back buffer
		D_HRESULT(m_SwapChain->ResizeBuffers(1, width, height, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
		ComPtr<ID3D11Resource> backBuffer;
		D_HRESULT(m_SwapChain->GetBuffer(0, __uuidof(ID3D11Resource), &backBuffer));
		D_HRESULT(m_Device->CreateRenderTargetView(backBuffer.Get(), nullptr, &m_Target));

		ComPtr<ID3D11Texture2D> depthStencilTexture2d;
		D3D11_TEXTURE2D_DESC descDepth = {};
		descDepth.Width = width;
		descDepth.Height = height;
		descDepth.MipLevels = 1u;
		descDepth.ArraySize = 1u;
		descDepth.Format = DXGI_FORMAT_D32_FLOAT;//DXGI_FORMAT_D32_FLOAT;
		descDepth.SampleDesc.Count = 1u;
		descDepth.SampleDesc.Quality = 0u;
		descDepth.Usage = D3D11_USAGE_DEFAULT;
		descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
		D_HRESULT(m_Device->CreateTexture2D(&descDepth, nullptr, &depthStencilTexture2d));
		D_HRESULT(m_Device->CreateDepthStencilView(depthStencilTexture2d.Get(), nullptr, &m_DepthStencilView));

		// 重新绑定一下
		m_Context->OMSetRenderTargets(1, m_Target.GetAddressOf(), m_DepthStencilView.Get());
		SetViewPort(0, 0, width, height);
	}

	void Graphics::SetViewPort(int leftX, int topY, int width, int height) {
		D3D11_VIEWPORT viewport;
		viewport.Width = static_cast<float>(width);
		viewport.Height = static_cast<float>(height);
		viewport.MinDepth = 0.0f;
		viewport.MaxDepth = 1.0f;
		viewport.TopLeftX = static_cast<float>(leftX);
		viewport.TopLeftY = static_cast<float>(topY);
		m_Context->RSSetViewports(1, &viewport);
	}

	void Graphics::ClearBuffer() {
		m_Context->ClearRenderTargetView(m_Target.Get(), m_clearColor);
		m_Context->ClearDepthStencilView(m_DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
	}

	void Graphics::Present() {
		D_HRESULT(m_SwapChain->Present(0, 0));
	}

}